from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *

from ui.Ui_execute_widget import Ui_widget_execute
from app.window.msg_box import Msg_box
import time
from worker.ssh_worker import Ssh_worker
from database.db import Database

def s_print (*args):
    t = time.localtime()
    t = time.strftime('%H:%M:%S')
    print(t,args)

class Execute_signal(QObject):
    new_script = Signal()
    remove_script = Signal()
    update_script = Signal()
    group_changed_script = Signal(str)
    select_changed_script = Signal(str)

    new_device = Signal()
    remove_device = Signal()
    update_device = Signal()
    group_changed_device = Signal(str)
    select_changed_device = Signal(str)
    # get_device_info = Signal(str)

    exectue_script = Signal(dict)

    script_manager = Signal(int)

    send_logs = Signal(str)

class Execute_widget(QWidget):
    
    cur_item: QListWidgetItem = None
    signal = Execute_signal()
    def __init__(self, parent=None):
        super(Execute_widget, self).__init__(parent)
        self.ui = Ui_widget_execute()
        self.ui.setupUi(self)

        self.device_id = -10
        self.scripts = {} # 格式 {'私有脚本':[{'name':xx,'content':xx,'textfsm':xx}]}
        self.devices = [] # 格式 [{'id','name','ip','port','...'}]
        self.disable_btn = False
        self.msg = Msg_box(self)

        self.init_ui()
        self.init_signal_slot()

        self.ui.checkBox_custom.setChecked(True)



    def init_ui(self):
        # 创建一个comboBox用来选择脚本分组
        self.listWidgetItem = QListWidgetItem()
        self.script_comboBox = QComboBox()
        self.ui.listWidget_script.addItem(self.listWidgetItem)
        self.ui.listWidget_script.setItemWidget(self.listWidgetItem,self.script_comboBox)
        self.ui.lineEdit_device_model.setDisabled(True)
        self.ui.lineEdit_device_position.setDisabled(True)
        self.ui.lineEdit_device_supplier.setDisabled(True)

    def init_signal_slot(self):
        self.ui.pushButton_exec.clicked.connect(self.slot_execute_script)
        self.ui.listWidget_script.itemClicked.connect(self.slot_click_item)
        self.script_comboBox.currentIndexChanged.connect(self.slot_comboBox_script_index_changed)
        self.ui.comboBox_device.currentIndexChanged.connect(self.slot_comboBox_device_index_changed)
        self.ui.checkBox_custom.stateChanged.connect(self.slot_checkBox_custom)

 


    def clear_data(self):
        self.ui.lineEdit_device_name.setText('')
        self.ui.lineEdit_device_ip.setText('')
        self.ui.lineEdit_port.setText('')
        self.ui.lineEdit_user.setText('')
        self.ui.lineEdit_password.setText('')
        self.ui.lineEdit_device_supplier.setText('')
        self.ui.lineEdit_device_model.setText('')
        self.ui.lineEdit_device_position.setText('')
        self.ui.textEdit_script_show.setText('')


    
    def load_private_scripts(self,device_id:int):
        db = Database()
        # 私有脚本
        if self.device_id >= 0:
            self.scripts['私有脚本'] = []
            script_id_list = db.select('private_script_device',['script_id'],f'device_id={device_id}')
            for script_id in script_id_list:
                script_data = db.select('scripts',['name','content','textfsm'],f'id={script_id[0]}')
                data = {
                    'name' : script_data[0][0],
                    'content' : script_data[0][1],
                    'textfsm' : script_data[0][2],
                }
                self.scripts['私有脚本'].append(data)
        db.close_conn()



    def load_public_scripts(self):
        db = Database()
        # 公有脚本
        group_list = db.select('script_group',['name'])
        for group in group_list:
            group_name = group[0]
            self.scripts[group_name] = []
            # 查询脚本数据
            script_list = db.select('scripts',['name','content','textfsm'],f'group_name="{group_name}"')
            for script_data in script_list:
                data = {
                    'name' : script_data[0],
                    'content' : script_data[1],
                    'textfsm' : script_data[2],
                }
                self.scripts[group_name].append(data)
        db.close_conn()

    def load_devices_data(self):
        '''
            加载所有设备数据 到 self.devices
        '''
        # 查询设备数据
        db = Database()
        fields = ['id','name','ip','port','user','password','supplier','model','position']
        device_list = db.select('devices',fields)
        del self.devices[:] # 清空列表
        for device in device_list:
            data = {
                'id':device[0],
                'name':device[1],
                'ip':device[2],
                'port':device[3],
                'user':device[4],
                'password':device[5],
                'supplier':device[6],
                'model':device[7],
                'position':device[8],
            }
            self.devices.append(data)
        db.close_conn()


    def get_device_data(self,deivce_id:int) -> dict:
        '''
            获取指定设备数据
        '''
        # 查询设备数据
        for device in self.devices:
            if device['id'] == deivce_id:
                return device


    def get_script_data(self,group_name,index:int) -> dict|None:
        '''
            获取脚本数据\n
            group_name:分组名称\n
            index:索引(listWidget的项目是从1创建的,索引传入时候应该-1)\n
            res:{'name':xx,'content':xx,'textfsm':xx}
        '''
        data_list = self.scripts.get(group_name)
        if not data_list:
            return 

        if len(data_list) <= index:
            return 
        
        return data_list[index]


    def is_group_name_exisit(self,group_name:str):
        for i in range(self.script_comboBox.count()):
            if self.script_comboBox.itemText(i) == group_name:
                return True
        return False    

    def is_group_name_valid(self,group_name:str) -> bool:
        for k in self.scripts:
            if k == group_name: return True
        return False

    def is_device_id_valid(self,device_id:int) -> bool:
        for i in range(len(self.devices)) :
                if device_id == self.devices[i]['id']:
                    return True
        return False
    
    def clear_script_item(self):
        # 清理listwidget
        max_row = self.ui.listWidget_script.count()
        for i in range(max_row-1,0,-1):
            self.ui.listWidget_script.takeItem(i)
    
    def set_script_item(self,group_name:str):
        '''
            设置新的分组 并刷新数据
        '''
        # 检测分组有效性
        if not self.is_group_name_valid(group_name): return

        self.clear_script_item()
       
        # 加载数据
        for data in self.scripts[group_name]:
            self.ui.listWidget_script.addItem(data['name'])

    
    def set_device_data(self,data:dict):
        self.ui.lineEdit_device_ip.setText(data['ip'])
        self.ui.lineEdit_port.setText(data['port'])
        self.ui.lineEdit_user.setText(data['user'])
        self.ui.lineEdit_password.setText(data['password'])
        self.ui.lineEdit_device_supplier.setText(data['supplier'])
        self.ui.lineEdit_device_model.setText(data['model'])
        self.ui.lineEdit_device_position.setText(data['position'])


    # ui操作相关槽函数
    #
    #


    def slot_click_item(self,item:QListWidgetItem):
        '''
            脚本 listWidget 点击槽函数
        '''
        index = self.ui.listWidget_script.row(item)
        group_name = self.script_comboBox.currentText()
        data = self.get_script_data(group_name,index-1)
        if not data:
            return
        self.ui.textEdit_script_show.setText(data['content'])
        self.ui.textEdit_TextFSM.setText(data['textfsm'])

    

    def slot_checkBox_custom(self,check_status:int):
        '''
            自定义选项开关槽函数
        '''
        if check_status == Qt.Checked:
            self.device_id = -1
            self.ui.lineEdit_device_ip.setDisabled(False)
            self.ui.lineEdit_port.setDisabled(False)
            self.ui.lineEdit_user.setDisabled(False)
            self.ui.lineEdit_password.setDisabled(False)
            self.ui.comboBox_device.setDisabled(True)
            # 删除私有脚本分组
            if self.script_comboBox.currentText() == '私有脚本':
                # 清理listwidget
                max_row = self.ui.listWidget_script.count()
                for i in range(max_row-1,0,-1):
                    self.ui.listWidget_script.takeItem(i)

            for i in range(self.script_comboBox.count()):
                if self.script_comboBox.itemText(i) == '私有脚本':
                    self.script_comboBox.removeItem(i)
                    break
            
            #加载当前公有脚本
            group_name = self.script_comboBox.currentText()
            self.set_script_item(group_name)
    
        if check_status == Qt.Unchecked:
            if self.device_id == -1:
                #添加私有脚本分组
                index = self.ui.comboBox_device.currentIndex()
                if len(self.devices) <= index: 
                    return
                self.device_id = self.devices[index]['id']
                self.load_private_scripts(self.device_id)
                # if not self.is_group_name_valid('私有脚本'):
                flag = True
                for i in range(self.script_comboBox.count()):
                    if self.script_comboBox.itemText(i) == '私有脚本':
                        flag = False
                if flag:
                    self.script_comboBox.addItem('私有脚本')

            self.ui.lineEdit_device_ip.setDisabled(True)
            self.ui.lineEdit_port.setDisabled(True)
            self.ui.lineEdit_user.setDisabled(True)
            self.ui.lineEdit_password.setDisabled(True)
            self.ui.comboBox_device.setDisabled(False)
        

    def slot_comboBox_script_index_changed(self):
        '''
            脚本分组选项切换 槽函数
        '''
        group_name = self.script_comboBox.currentText()
        self.set_script_item(group_name)

    

    def slot_comboBox_device_index_changed(self,index:int):
        if self.ui.checkBox_custom.isChecked():
            return
        if index < 0: return
        if index >= len(self.devices) : return
        device_id = self.devices[index]['id']
        # 加载私有脚本
        self.load_private_scripts(device_id)
        # 创建私有脚本分组
        if not self.is_group_name_exisit('私有脚本'):
            self.script_comboBox.addItem('私有脚本')

        # 重载脚本分组数据
        if self.script_comboBox.currentText() == '私有脚本':
            self.set_script_item('私有脚本')

        # 设置设备数据
        device_data = self.get_device_data(device_id)
        self.set_device_data(device_data)


    def slot_reload_data(self):
        '''
            当切换到当前页面时,重载一次数据
        '''
        # 保留重载前设备id
        pre_device_id = -2
        index = self.ui.comboBox_device.currentIndex()
        if index != -1 and index < len(self.devices):
            pre_device_id = self.devices[index]['id']

        # 保留当前分组名称
        pre_group_name = self.script_comboBox.currentText()

        # 清理数据
        self.devices.clear()
        self.scripts.clear()
        self.script_comboBox.clear()
        self.clear_script_item()
        self.ui.comboBox_device.clear() # 会发送 index_changed 信号

        # 加载所有设备数据
        self.load_devices_data()

        # 加载公有脚本数据
        self.load_public_scripts()

        # 重建comboBox_device 会发送 index_changed 信号
        for device in self.devices:
            self.ui.comboBox_device.addItem(device['name']) 
        # 检测是否指定设备
        if not self.ui.checkBox_custom.isChecked() and self.is_device_id_valid(pre_device_id):
            # 设置设备
            for i in range(len(self.devices)):
                if self.devices[i]['id'] == pre_device_id:
                    self.ui.comboBox_device.setCurrentIndex(i) #会发送 index_changed 信号
                    break
        
        # 重建公有脚本分组 
        for name in self.scripts:
            if name != '私有脚本':
                self.script_comboBox.addItem(name)

        # 检测原分组的有效性
        if self.is_group_name_valid(pre_group_name) and pre_group_name != '私有脚本':
            # 重置原分组数据设置
            self.script_comboBox.setCurrentText(pre_group_name)


    def slot_device_excute_script(self,device_id:int):
        self.ui.checkBox_custom.setChecked(False)
        self.device_id = device_id
        for i in range(len(self.devices)):
            if self.devices[i]['id'] == device_id:
                self.ui.comboBox_device.setCurrentIndex(i)
                # 设置设备数据
                device_data = self.get_device_data(device_id)
                self.set_device_data(device_data)
                break
        





    def slot_execute_script(self):
        if self.disable_btn:
            QMessageBox.warning(self, "警告", "正在执行任务,请勿重新执行!", QMessageBox.Yes)
            return
        if self.ui.textEdit_script_show.toPlainText() == '':
            QMessageBox.warning(self, "警告", "脚本不为空!", QMessageBox.Yes)
            return
        
        script_item = self.ui.listWidget_script.currentItem()
        script_name = '无'
        if  script_item is not None :
            script_name = script_item.text()
        current_time = time.localtime()
        fmt_time = time.strftime('%Y-%m-%d %H:%M:%S',current_time)
        log_data = {
            'device_name': self.ui.comboBox_device.currentText(),
            'script_name': script_name,
            'cmds' : self.ui.textEdit_script_show.toPlainText(),
            'ip' : self.ui.lineEdit_device_ip.text(),
            'port' : self.ui.lineEdit_port.text(),
            'user':self.ui.lineEdit_user.text(),
            'password':self.ui.lineEdit_password.text(),
            'supplier':self.ui.lineEdit_device_supplier.text(),
            'model' : self.ui.lineEdit_device_model.text(),
            'position' : self.ui.lineEdit_device_position,
            'exec_time':fmt_time,
        }
        ssh_data = {
            'ip' : self.ui.lineEdit_device_ip.text(),
            'port' : self.ui.lineEdit_port.text(),
            'user':self.ui.lineEdit_user.text(),
            'password':self.ui.lineEdit_password.text(),
            'cmds' : self.ui.textEdit_script_show.toPlainText(),
            'textfsm':self.ui.textEdit_TextFSM.toPlainText(),

            'device_name': self.ui.comboBox_device.currentText(),
            'script_name': self.ui.listWidget_script.currentItem().text()
        }
        
        # 创建线程
        self.workerThread = QThread(self)
        self.workerThread.setObjectName('workerThread')
        self.worker = Ssh_worker(ssh_data)
        self.worker.moveToThread(self.workerThread)
        self.workerThread.started.connect(self.worker.start_work)
        self.worker.finished.connect(self.workerThread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        # self.worker.finished.connect(self.task_done)
        self.worker.signal.send_logs.connect(self.send_logs)
        # self.worker.signal.timer_stop.connect(self.timer_stop)
        self.workerThread.finished.connect(self.workerThread.deleteLater)

        self.workerThread.start()

        # 信息输出
        self.timer_ip = ssh_data["ip"]
        self.timer_time = 1
        # self.timer.start(1000)

        self.disable_btn = True


    def send_logs(self,text:str):
        print(text)